package sjtu.ist.warehouse4ws.tool.parser;

import java.io.File;
import java.io.IOException;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;

import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.parsers.ParserConfigurationException;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.NamedNodeMap;
import org.w3c.dom.NodeList;
import org.xml.sax.SAXException;

import sjtu.ist.warehouse4ws.epc2bpmn.ParserEpc;
import sjtu.ist.warehouse4ws.model.Domainmodelstate;
import sjtu.ist.warehouse4ws.model.Epcunit;
import sjtu.ist.warehouse4ws.model.Epcunits;
import sjtu.ist.warehouse4ws.model.Functionpoint;

public class EpcParser {
	private File file;
	private Document doc;
	private Epcunits epcUnits;

	public EpcParser(File file) {
		this.file = file;
	}

	public void parse() {
		if (file == null) {
			System.out.println("未提供模型文件");
			return;
		}
		DocumentBuilderFactory dbf = DocumentBuilderFactory.newInstance();
		DocumentBuilder db = null;
		try {
			db = dbf.newDocumentBuilder();
			doc = db.parse(file);
		} catch (ParserConfigurationException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (SAXException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		} catch (IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
		epcUnits = new Epcunits();
		parseEpcUnits();
	}

	/**
	 * 解析EPC模型
	 */
	private void parseEpcUnits() {
		
		NodeList nodelist = doc.getElementsByTagName("epc");

		NamedNodeMap head = nodelist.item(0).getAttributes();
		String headName = head.item(1).getNodeValue();

		Element node1 = (Element) nodelist.item(0); // show the epc Node
		// print the node tag name

		NodeList epcList = node1.getChildNodes(); // get the children of epc
													// Node

		Epcunit start = new Epcunit(); // the start point of the process
		start.setType("start");
		start.setName(headName);
		start.setId(0);
		epcUnits.getEpcUnits().add(start);

		int next = Integer.parseInt(epcList.item(1).getAttributes().item(0)
				.getNodeValue());

		epcUnits.bulidRelationship(0, next);

		int max = 0;
		for (int i = 1; i < epcList.getLength(); i = i + 2) {
			Element typeNode = (Element) epcList.item(i);
			String type = typeNode.getTagName(); // get the type value of the
													// tag;

			NodeList valueNodes = typeNode.getChildNodes();

			Element nameNode = (Element) valueNodes.item(1);

//			if (nameNode == null) {
//				continue;
//			}

			if (type != "arc" && type != "relation") {
				NamedNodeMap attributes = typeNode.getAttributes(); // get the
																	// attribute's
																	// value in
																	// the tag
				int nodeId = Integer
						.parseInt(attributes.item(0).getNodeValue()); // get the
																		// id of
																		// the
																		// node
				if (max < nodeId)
					max = nodeId;
				Epcunit nodeData = new Epcunit(); // set the type
				if (type != "and" && type != "or" && type != "xor") {
					nodeData.setType(type);
					nodeData.setName(nameNode.getFirstChild().getNodeValue()); // set
																				// the
																				// name
				} else {
					nodeData.setType("connector");
					nodeData.setName(type);
				}

				nodeData.setId(nodeId);

				epcUnits.getEpcUnits().add(nodeData);

			} else if (type == "arc") {
				NamedNodeMap nexts = nameNode.getAttributes();

				int targetId = Integer.parseInt(nexts.item(1).getNodeValue());
				int sourceId = Integer.parseInt(nexts.item(0).getNodeValue());

				epcUnits.bulidRelationship(sourceId, targetId);

			}

			else {
				NamedNodeMap nexts = typeNode.getAttributes();

				int targetId = Integer.parseInt(nexts.item(1).getNodeValue());
				int sourceId = Integer.parseInt(nexts.item(0).getNodeValue());

				epcUnits.findSourceDataById(sourceId).setParticipant(targetId);

			}

		}
		Epcunit end = new Epcunit(); // the start point of the process
		end.setType("end");
		end.setName("End");
		end.setId(max + 1);
		epcUnits.getEpcUnits().add(end);
	}

	/**
	 * 检测Epc模型一致性
	 * 
	 * @param stateList
	 * @param funList
	 * @return
	 */
	public String checkEpcConsistence(List<Domainmodelstate> stateList,
			List<Functionpoint> funList) {
		StringBuilder result = new StringBuilder();

		HashMap<String, Integer> stateMap = new HashMap<String, Integer>();
		HashMap<String, Integer> functionMap = new HashMap<String, Integer>();
		for (Domainmodelstate ds : stateList) {
			stateMap.put(ds.getId(), 0);
		}
		for (Functionpoint fp : funList) {
			functionMap.put(fp.getId(), 0);
		}
		List<Epcunit> list = epcUnits.getEpcUnits();
		for (Epcunit epcunit : list) {
			if (epcunit.getType() == "event") {
				String eName = epcunit.getName();
				int find = 0;
				for (Domainmodelstate ds : stateList) {
					if (ds.getEnName().equals(eName)) {
						find = 1;
						stateMap.put(ds.getId(), 1);
						break;
					}
				}
				if (find == 0)
					result.append("状态" + eName + "没有找到对应的上传模型"
							+ PackageParser.newline); // epcunit 没有找到类似的单元

			}
			if (epcunit.getType() == "function") {
				String fName = epcunit.getName();
				int find = 0;
				for (Functionpoint fp : funList) {
					if (fp.getEnName().equals(fName)) {
						find = 1;
						functionMap.put(fp.getId(), 1);
						break;
					}
				}
				if (find == 0)
					result.append("功能" + fName + "没有找到对应的上传模型"
							+ PackageParser.newline);
			}

		}
		if (functionMap.containsValue(0)) {
			// 采用Iterator遍历HashMap
			Iterator it = functionMap.keySet().iterator();
			while (it.hasNext()) {

				String key = (String) it.next();

				if (functionMap.get(key) == 0)
					result.append(key + "没有找到对应的功能模型。" + PackageParser.newline);
			}
		}
		if (stateMap.containsValue(0)) {
			// 采用Iterator遍历HashMap
			Iterator it = stateMap.keySet().iterator();
			while (it.hasNext()) {

				String key = (String) it.next();

				if (stateMap.get(key) == 0)
					result.append(key + "没有找到对应的事件模型。" + PackageParser.newline);
			}
		}

		return result.toString();
	}

	public Epcunits getEpcUnits() {
		return epcUnits;
	}

}
